#include "executer.h"

#include <QRegExp>
#include <QTimer>

#ifdef  Q_OS_LINUX
#include <signal.h>
#include <sys/types.h>
#else
#include <stdlib.h>
#endif

/* 500 milisecond */
#define    READ_INTERVAL 2000

Executer::Executer(QObject * parent, QString dirname, QString exe, QString param)
    : QThread(parent)
{
    m_parent = parent;
    m_executableName = exe;
    m_parameters = param;
    m_workDirectory  =  dirname;

    m_started = false;
    m_exitCode = 0;
    m_status = QProcess::NormalExit;

    m_readTimer = NULL;

    connect(m_parent, SIGNAL(stopExecute()), this, SLOT(slotStopExec()) );
    connect(this, SIGNAL(finished()), this, SLOT(slotThreadFinished()));
    connect(this, SIGNAL(terminated()), this, SLOT(slotThreadFinished()));

}

Executer::~Executer()
{
    if (m_readTimer) {
        m_readTimer->stop();
        delete m_readTimer;
        m_readTimer = NULL;
    }
}

void Executer::run()
{

    qRegisterMetaType<enum QProcess::ExitStatus>("QProcess::ExitStatus");

    m_target = new QProcess();
    connect(m_target, SIGNAL(readyReadStandardOutput()), this, SLOT(slotOutputMessage()));
    connect(m_target, SIGNAL(readyReadStandardError()), this, SLOT(slotOutputMessage()));
    connect(m_target, SIGNAL(started()), this, SLOT(slotTargetStarted()));
    connect(m_target, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(slotTargetFinished(int, QProcess::ExitStatus)));
    setEnvironment( m_target );

    m_started = false;
    m_target->start(m_executableName, m_parameters.split(QRegExp("\\s+")));
    //qWarning ("Starting...");
    if (!m_target->waitForStarted(10000)) {
        delete m_target;
        m_target = NULL;
        m_started = false;
        return;
    }
    //qWarning ("started...");
    m_started = true;
    //m_target->waitForFinished(-1);
    while (exec()) {
        m_target->waitForFinished(10);
    }
    //qWarning ("finished");
}

void Executer::setEnvironment(QProcess *process)
{
    process->setWorkingDirectory(m_workDirectory);
    QStringList env = QProcess:: systemEnvironment ();
    process->setEnvironment( env );
}

void Executer::slotOutputMessage()
{
    if (!m_target)
        return;

    //m_readTimer->stop();
    QString message;
    message = QString::fromLocal8Bit(m_target->readAllStandardOutput());
    m_stdoutStr += message;

    message = QString::fromLocal8Bit(m_target->readAllStandardError());
    m_stderrStr += message;
    if (!m_stdoutStr.isEmpty()) {
        QString s = m_stdoutStr.section('\n', 0, -2);
        m_stdoutStr = m_stdoutStr.section('\n', -1);
        emit outputMessage(s, false);
    }
    if (!m_stderrStr.isEmpty()) {
        QString s = m_stderrStr.section('\n', 0, -2);
        m_stderrStr = m_stderrStr.section('\n', -1);
        emit outputMessage(s, true);
    }
    //m_readTimer->start(READ_INTERVAL);
}

void Executer::slotThreadFinished()
{
    //qWarning ("Thread finished");
    emit execFinished(m_started, m_exitCode, m_status);
    deleteLater();
}

void Executer::slotTargetFinished(int code, QProcess::ExitStatus status)
{
    //qWarning ("Target finished");
    m_started = true;
    m_exitCode = code;
    m_status = status;

    QProcess *process = (QProcess*)sender();
    QString message;
    message = QString::fromLocal8Bit(process->readAllStandardOutput());
    m_stdoutStr += message;

    message = QString::fromLocal8Bit(process->readAllStandardError());
    m_stderrStr += message;

    if (!m_stdoutStr.isEmpty()) {
        emit outputMessage(m_stdoutStr, false);
        m_stdoutStr = "";
    }
    if (!m_stderrStr.isEmpty()) {
        emit outputMessage(m_stderrStr, true);
        m_stderrStr = "";
    }

    m_target->deleteLater();
    m_target = NULL;

    quit();
}

void Executer::slotStopExec()
{
#ifdef    Q_OS_WIN
    //qWarning ("Terminate");
    m_target->terminate();
    if (!m_target->waitForFinished(1000)) {
        //qWarning ("Kill");
        m_target->kill();
    }
#else
    //qWarning ("Kill");
    Q_PID pid = m_target->pid();
    kill (pid, SIGKILL);
#endif
}

void Executer::slotTargetStarted()
{
#if 0
    m_readTimer = new QTimer();
    m_readTimer->setSingleShot(false);
    connect(m_readTimer, SIGNAL(timeout()), this, SLOT(slotOutputMessage()));
    m_readTimer->start(READ_INTERVAL);
#endif
}
